#ifndef _PLAYER_H
#define _PLAYER_H

#include "../includes.h"

//{ ********** player class **********

class cPlayer: public cSprite
{
    public:

        // setup player exclusive vars
        std::string name;
        unsigned short lives, health;
        unsigned int XP, level, money;
        bool inWave; unsigned short wave, enemiesInWave;
        enum eWeapon {normal=0, automatic=1, laser=2} weaponType;
        unsigned short ammo, rockets;
        bool hit;
        unsigned char foreKey, backKey;

        // constructor and destructor prototypes
        cPlayer(std::string pImage, unsigned short pImageID, unsigned short pSpriteID);
        ~cPlayer();

        // override cSprite's virtual update function
        virtual void update(void);
        void startWave(void);

    //load and save settings, set as private because they should only be called from constructor and destructor
    private:
        void LoadPlayerSettings(std::string fileName);
        void SavePlayerSettings(std::string fileName);

};

cPlayer::cPlayer(std::string pImage, unsigned short pImageID, unsigned short pSpriteID)
{
    // set main image and sprite properties
    image = pImage; imageID = pImageID; spriteID = pSpriteID;
    X = (dbScreenWidth() / 2); Y = (dbScreenHeight() / 2);
    speed = 300.0f; copy = false; inWave = false; wave = 0; enemiesInWave = 10;
    weaponType = normal; ammo = 0; rockets = 0;
    foreKey = 0x57; backKey = 0x53;

    // load image if it doesn't exist
    if (!dbIsImage(imageID))
        dbLoadImage(image, imageID);

    // setup sprite
    midX = dbImageWidth(imageID) / 2; midY = dbImageHeight(imageID) / 2;
    dbSprite(spriteID, 0, 0, imageID); dbOffsetSprite(spriteID, midX, midY); dbSprite(spriteID, (int)X, (int)Y, imageID);
    dbSetSpritePriority(spriteID, 2); // sprite priority is 2, so it gets drawn on same level as aim reticle
    //LoadPlayerSettings("saves/player.dat");
}

cPlayer::~cPlayer()
{
    //save player settings and data at end of game
    SavePlayerSettings("saves/player.dat");

    // delete player image and sprite
    if (dbIsImage(imageID))
    {
        dbDeleteSprite(spriteID);
        dbDeleteImage(imageID);
    }
}

void cPlayer::update(void)
{
    // if the player is offscreen, put the player back on screen
    if (X <= 0) X = 0; if (X >= dbScreenWidth()) X = dbScreenWidth();
    if (Y <= 0) Y = 0; if (Y >= dbScreenHeight()) Y = dbScreenHeight();

    // update sprite position and angle
    dbSprite(spriteID, (int)X, (int)Y, imageID);
    dbRotateSprite(imageID, angle);
    return;
}

void cPlayer::LoadPlayerSettings(std::string fileName)
{
    M1U_OpenDataFileToRead(1, fileName);
    name = M1U_DataFileString(1);
    money = M1U_DataFileInteger(1);
    XP = M1U_DataFileInteger(1);
    level = M1U_DataFileInteger(1);
    foreKey = M1U_DataFileInteger(1);
    backKey = M1U_DataFileInteger(1);
    M1U_CloseDataFile(1);
    return;
}

void cPlayer::SavePlayerSettings(std::string fileName)
{
    M1U_OpenDataFileToWrite(1, fileName);
    M1U_WriteDataFileString(1, name);
    M1U_WriteDataFileInteger(1, money);
    M1U_WriteDataFileInteger(1, XP);
    M1U_WriteDataFileInteger(1, level);
    M1U_WriteDataFileInteger(1, foreKey);
    M1U_WriteDataFileInteger(1, backKey);
    M1U_CloseDataFile(1);
    return;
}

void cPlayer::startWave(void)
{
    // hide the cursor
    ShowCursor(false); dbShowSprite(2);
    ++wave; inWave = true; enemiesInWave += 5;
    return;
}

//} ********** player class **********

//{ ********** player bullet class **********

class cPlayerBullet: public cSprite
{
    public:

        static unsigned int lastFired, nextBullet;
        void fire(const cPlayer& player);
        // constructor and destructor prototypes
        cPlayerBullet(std::string pImage, int pImageID, int pSpriteID, const cPlayer& player);
        cPlayerBullet(const cPlayerBullet& playerBullet);
        ~cPlayerBullet();
};

cPlayerBullet::cPlayerBullet(std::string pImage, int pImageID, int pSpriteID, const cPlayer& player)
{
    // set up sprite variables
    image = pImage; imageID = pImageID; spriteID = pSpriteID;
    X = player.X; Y = player.Y; angle = player.angle;
    speed = -800.0f; copy = false;

    // if imagenum doesn't exist, load it
    if (!dbIsImage(imageID))
        dbLoadImage(image, imageID);

    //make sprite at player location
    dbSprite(spriteID, (int)X, (int)Y, imageID);

    // get the middle of the sprite and offset it there
    midX = dbImageWidth(imageID) / 2; midY = dbImageHeight(imageID) / 2;
    dbOffsetSprite(spriteID, midX, midY);

    // hide the sprite, it will be shown when fired
    dbHideSprite(spriteID);
}

cPlayerBullet::cPlayerBullet(const cPlayerBullet& playerBullet)
{
    // set up sprite variables
    image = playerBullet.image; imageID = playerBullet.imageID; spriteID = playerBullet.spriteID;
    X = playerBullet.X; Y = playerBullet.Y; angle = playerBullet.angle; speed = playerBullet.speed;

    //set current copy to false, and old copy to true, since copy construct only gets called when resizing a vector
    copy = false;
    playerBullet.copy = true;

    // if imagenum doesn't exist, load it
    if (!dbIsImage(imageID))
        dbLoadImage(image, imageID);

    // set sprite to old sprite location, and rotate to old angle
    dbSprite(spriteID, (int)X, (int)Y, imageID);
    dbRotateSprite(spriteID, angle);
}

cPlayerBullet::~cPlayerBullet()
{
    // if the iteration is being destroyed, not copied, then delete the sprite.
    if (copy==false)
    {
        if (dbIsSprite(spriteID))
            dbDeleteSprite(spriteID);
    }
}

void cPlayerBullet::fire(const cPlayer& player)
{
    // start bullet at player position and angle
    X = player.X; Y = player.Y; angle = player.angle;

    dbSprite(spriteID, X, Y, imageID);
    dbRotateSprite(spriteID, angle);
    dbShowSprite(spriteID); hidden = false;

    // loop bullets, prevent crash when going out of vector bounds.
    if (nextBullet == 9)
        nextBullet = 0;
    else
        nextBullet += 1;


    lastFired = dbTimer();
}

//} ********** player bullet class **********

#endif
